package com.echo.yixiaowu.feature.components

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.awaitLongPressOrCancellation
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.gestures.drag
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SheetState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.PointerInputScope
import androidx.compose.ui.input.pointer.changedToUp
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastForEach
import com.echo.yixiaowu.feature.main.home.DraggableItem
import com.echo.yixiaowu.feature.main.home.HomeEvent
import com.echo.yixiaowu.feature.main.home.SortState
import java.util.Collections
import kotlin.coroutines.cancellation.CancellationException

/**
 * 封装了用于编辑分区的底部弹出框UI
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditSectionsSheet(
    sheetState: SheetState,
    sortState: SortState,
    onDismissRequest: () -> Unit,
    onConfirm: () -> Unit,
    onEvent: (HomeEvent) -> Unit
) {
    ModalBottomSheet(
        onDismissRequest = onDismissRequest,
        sheetState = sheetState
    ) {
        DraggableListContent(
            menuItems = sortState.items,
            isLoading = sortState.isLoading,
            onEvent = onEvent,
            onConfirm = onConfirm
        )
    }
}

@Composable
fun DraggableListContent(
    menuItems: List<DraggableItem>,
    isLoading: Boolean,
    onEvent: (HomeEvent) -> Unit,
    onConfirm: () -> Unit
) {
    var draggingItemIndex by remember { mutableStateOf<Int?>(null) }
    var dragOffsetY by remember { mutableFloatStateOf(0f) }
    val listState = rememberLazyListState()
    val menuList = remember {
        menuItems.map { it.copy() }.toMutableStateList()
    }
    val isChangeMenu = menuList.toList() != menuItems.toList()
    val hapticFeedBack = LocalHapticFeedback.current

    if (isLoading) {
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .height(260.dp), contentAlignment = Alignment.Center
        ) {
            CircularProgressIndicator()
        }
        return
    }
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp),
        horizontalArrangement = Arrangement.SpaceBetween, // 将剩余空间放在元素之间，从而将它们推向两端
        verticalAlignment = Alignment.CenterVertically   // 让文本在垂直方向上居中对齐
    ) {
        Text(text = "分区")
        Text(fontStyle = FontStyle.Normal, text = "长按调整顺序")
    }
    LazyColumn(
        state = listState,
        modifier = Modifier
            .fillMaxWidth()
            .height(440.dp),
        contentPadding = PaddingValues(16.dp),
    ) {
        itemsIndexed(menuList, key = { _, item -> item.id }) { index, item ->
            val currentIndex by rememberUpdatedState(index)
            val baseModifier = Modifier.fillMaxWidth()
            var isPressed by remember { mutableStateOf(false) }
            val scaleReduce by animateFloatAsState(
                targetValue = if (isPressed) 0.95f else 1f,
                label = "scaleReduceAnimation"
            )

            // 元素拖动时，取消animateItem
            val animationModifier = if (index != draggingItemIndex) {
                baseModifier.animateItem()
            } else {
                baseModifier
            }
            Box(modifier = animationModifier
                .pointerInput(item.id) {
                    detectDragGesturesAfterLongPress(
                        onTap = {
                            isPressed = false
                        },
                        onPress = {
                            isPressed = true
                        },
                        onDragStart = {
                            // 拖动开始，记录当前的索引
                            draggingItemIndex = currentIndex
                            isPressed = false
                            hapticFeedBack.performHapticFeedback(HapticFeedbackType.LongPress)
                        }, onDragEnd = {
                            // 拖动结束时，重置状态
                            draggingItemIndex = null
                            isPressed = false
                            dragOffsetY = 0f
                        }, onDragCancel = {
                            // 拖动取消，重置状态
                            draggingItemIndex = null
                            isPressed = false
                            dragOffsetY = 0f
                        }, onDrag = { change, dragAmount ->
                            change.consume()
                            val currentDraggingItem =
                                draggingItemIndex ?: return@detectDragGesturesAfterLongPress
                            dragOffsetY += dragAmount.y
                            val layoutInfo = listState.layoutInfo.visibleItemsInfo
                            val draggingItemLayout =
                                layoutInfo.firstOrNull { it.index == currentDraggingItem }
                                    ?: return@detectDragGesturesAfterLongPress
                            val targetItem = if (dragAmount.y > 0) {
                                layoutInfo.firstOrNull { it.index == currentDraggingItem + 1 }
                            } else if (dragAmount.y < 0) {
                                layoutInfo.firstOrNull { it.index == currentDraggingItem - 1 }
                            } else {
                                null
                            }

                            if (targetItem != null) {
                                val draggingItemCenterY =
                                    draggingItemLayout.offset + draggingItemLayout.size / 2 + dragOffsetY
                                val targetItemCenterY = targetItem.offset + targetItem.size / 2
                                val shouldSwap = if (dragAmount.y > 0) {
                                    // 向下拖动
                                    draggingItemCenterY > targetItemCenterY
                                } else {
                                    // 向上拖动
                                    draggingItemCenterY < targetItemCenterY
                                }

                                if (shouldSwap) {
                                    val targetIndex = targetItem.index
                                    val draggedItemInitialOffset = draggingItemLayout.offset
                                    val targetItemInitialOffset = targetItem.offset
                                    dragOffsetY += (draggedItemInitialOffset - targetItemInitialOffset)
                                    Collections.swap(menuList, currentDraggingItem, targetIndex)
                                    draggingItemIndex = targetIndex
                                }
                            }
                        })
                    detectTapGestures(
                        onPress = {
                            isPressed = true
                        },
                        onTap = {
                            isPressed = false
                        }
                    )
                }
                .graphicsLayer {
                    // 如果当前是正在被拖动的元素，则应用Y轴位移和放大效果
                    if (index == draggingItemIndex) {
                        translationY = dragOffsetY
                        scaleX = 1.05f
                        scaleY = 1.05f
                        alpha = 0.8f
                    } else {
                        scaleX = scaleReduce
                        scaleY = scaleReduce
                    }
                }) {
                // 列表项的UI
                val elevation by animateFloatAsState(if (index == draggingItemIndex) 8f else 2f)
                Card(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(vertical = 4.dp),
                    elevation = CardDefaults.cardElevation(defaultElevation = elevation.dp)
                ) {
                    Text(
                        text = item.title,
                        modifier = Modifier.padding(16.dp),
                        fontSize = 18.sp,
                        fontWeight = FontWeight.SemiBold
                    )
                }
            }
        }
        item {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 8.dp),
                contentAlignment = Alignment.Center // 内容居中
            ) {
                Button(modifier = Modifier.width(140.dp),
                    enabled = isChangeMenu,
                    onClick = {
                        onEvent(HomeEvent.OnSaveChanges(menuList))
                        onConfirm()
                    }) {
                    Text("确认")
                }
            }
        }
    }
}

suspend fun PointerInputScope.detectDragGesturesAfterLongPress(
    onTap: () -> Unit = {},
    onPress: () -> Unit = {},
    onDragStart: (Offset) -> Unit = {},
    onDragEnd: () -> Unit = {},
    onDragCancel: () -> Unit = {},
    onDrag: (change: PointerInputChange, dragAmount: Offset) -> Unit
) {
    awaitEachGesture {
        try {
            val down = awaitFirstDown(requireUnconsumed = false)
            onPress()
            val drag = awaitLongPressOrCancellation(down.id)
            if (drag != null) {
                onDragStart.invoke(drag.position)
                if (
                    drag(drag.id) {
                        onDrag(it, it.positionChange())
                        it.consume()
                    }
                ) {
                    // consume up if we quit drag gracefully with the up
                    currentEvent.changes.fastForEach { if (it.changedToUp()) it.consume() }
                    onDragEnd()
                } else {
                    onDragCancel()
                }
            } else {
                onTap()
            }
        } catch (c: CancellationException) {
            onDragCancel()
            throw c
        }
    }
}
